home *** CD-ROM | disk | FTP | other *** search
- #include "lib.h"
- #include <memory.h>
-
- # define _LMALLOC lmalloc
- # define _LREALLOC lrealloc
- # define _LCALLOC lcalloc
-
-
- /* replace undef by define */
- #undef DEBUG /* check assertions */
- #undef SLOWDEBUG /* some extra test loops (requires DEBUG) */
-
- #ifdef DEBUG
- #define ASSERT(b) if (!(b)) assert_failed();
- #else
- #define ASSERT(b) /* empty */
- #endif
-
- #ifdef i8088
- #define ptrint int
- #endif
- #ifdef ATARI_ST
- #define ptrint long
- #endif
-
- #define BRKSIZE ((unsigned long)1024)
- #define PTRSIZE (sizeof(char *))
-
- #ifdef __GNUC__
- #define Align(x,a) (( ((ptrint)(x)) + ((ptrint)a - 1L)) & ~((ptrint)a - 1L))
- #else
- #define Align(x,a) (((x) + (a - 1)) & ~(a - 1))
- #endif
-
- #define NextSlot(p) (* (char **) ((p) - PTRSIZE))
- #define NextFree(p) (* (char **) (p))
-
- /*
- * A short explanation of the data structure and algorithms.
- * An area returned by malloc() is called a slot. Each slot
- * contains the number of bytes requested, but preceeded by
- * an extra pointer to the next the slot in memory.
- * '_bottom' and '_top' point to the first/last slot.
- * More memory is asked for using brk() and appended to _top.
- * The list of free slots is maintained to keep malloc() fast.
- * '_empty' points the the first free slot. Free slots are
- * linked together by a pointer at the start of the
- * user visable part, so just after the next-slot pointer.
- * Free slots are merged together by free().
- */
-
- #ifndef __STDC__ /* for __STDC__ pick up proto from <std.h> */
- extern _VOIDSTAR sbrk();
- extern _VOIDSTAR brk();
- #endif
- static char *_bottom, *_top, *_empty;
-
- static int grow(len)
- unsigned long len;
- {
- register char *p;
-
- ASSERT(NextSlot(_top) == 0);
- p = (char *) Align((ptrint)_top + len, BRKSIZE);
- if (p < _top || brk(p) != 0)
- return(0);
- NextSlot(_top) = p;
- NextSlot(p) = 0;
- free(_top);
- _top = p;
- return(1);
- }
-
- #ifndef __MSHORT__
- asm(".text; .even; .globl _malloc; _malloc:"); /* dept of dirty tricks */
- #endif
- _VOIDSTAR _LMALLOC (size)
- unsigned long size;
- {
- register char *prev, *p, *next, *new;
- register unsigned long len;
- register short ntries;
-
- if (size == 0)
- size = PTRSIZE; /* avoid slots less that 2*PTRSIZE */
- for (ntries = 0; ntries < 2; ntries++) {
- len = Align(size, PTRSIZE) + PTRSIZE;
- if (_bottom == 0) {
- p = sbrk((int)(2 * (int)PTRSIZE));
- p = (char *) Align((ptrint)p, PTRSIZE);
- p += PTRSIZE;
- _top = _bottom = p;
- NextSlot(p) = 0;
- }
- #ifdef SLOWDEBUG
- for (p = _bottom; (next = NextSlot(p)) != 0; p = next)
- ASSERT(next > p);
- ASSERT(p == _top);
- #endif
- for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
- next = NextSlot(p);
- new = p + len;
- if (new > next)
- continue; /* too small */
- if (new + PTRSIZE < next) { /* too big, so split */
- /* + PTRSIZE avoids tiny slots on free list */
- NextSlot(new) = next;
- NextSlot(p) = new;
- NextFree(new) = NextFree(p);
- NextFree(p) = new;
- }
- if (p < _bottom)
- return(0);
- if (prev)
- NextFree(prev) = NextFree(p);
- else
- _empty = NextFree(p);
- return(p);
- }
- if (grow(len) == 0)
- break;
- }
- ASSERT(ntries != 2);
- return(0);
- }
-
- #ifndef __MSHORT__
- asm(".text; .even; .globl _realloc; _realloc:"); /* dept of dirty tricks */
- #endif
- _VOIDSTAR _LREALLOC(old, size)
- _VOIDSTAR old;
- unsigned long size;
- {
- register char *prev, *p, *next, *new;
- register unsigned long len, n;
-
- if(old == (_VOIDSTAR)0) return _LMALLOC(size);
-
- len = Align(size, PTRSIZE) + PTRSIZE;
- next = NextSlot(old);
- n = (unsigned long)(next - (char *)old); /* old length */
- /*
- * extend old if there is any free space just behind it
- */
- for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
- if (p > next)
- break;
- if (p == next) { /* 'next' is a free slot: merge */
- NextSlot(old) = NextSlot(p);
- if (prev)
- NextFree(prev) = NextFree(p);
- else
- _empty = NextFree(p);
- next = NextSlot(old);
- break;
- }
- }
- new = old + len;
- /*
- * Can we use the old, possibly extended slot?
- */
- if (new <= next) { /* it does fit */
- if (new + PTRSIZE < next) { /* too big, so split */
- /* + PTRSIZE avoids tiny slots on free list */
- NextSlot(new) = next;
- NextSlot(old) = new;
- free(new);
- }
- return(old);
- }
- if ((new = _LMALLOC(size)) == 0) /* it didn't fit */
- return(0);
- bcopy(old, new, (long)n); /* n < size */
- free(old);
- return(new);
- }
-
- #ifndef __MSHORT__
- asm(".text; .even; .globl _calloc; _calloc:"); /* dept of dirty tricks */
- #endif
- _VOIDSTAR _LCALLOC(n, size)
- unsigned long n, size;
- {
- register char *cp;
-
- n *= size;
- cp = _LMALLOC(n);
- if (cp == (char *)0)
- return ((char *)0);
- bzero(cp, (long)n);
- return(cp);
- }
-
- void free(p)
- _VOIDSTAR p;
- {
- register char *prev, *next;
-
- ASSERT(NextSlot(p) > p);
- for (prev = 0, next = _empty; next != 0; prev = next, next = NextFree(next))
- if ((char *)p < next)
- break;
- NextFree(p) = next;
- if (prev)
- NextFree(prev) = p;
- else
- _empty = p;
- if (next) {
- ASSERT(NextSlot(p) <= next);
- if (NextSlot(p) == next) { /* merge p and next */
- NextSlot(p) = NextSlot(next);
- NextFree(p) = NextFree(next);
- }
- }
- if (prev) {
- ASSERT(NextSlot(prev) <= p);
- if (NextSlot(prev) == p) { /* merge prev and p */
- NextSlot(prev) = NextSlot(p);
- NextFree(prev) = NextFree(p);
- }
- }
- }
-
- #ifdef DEBUG
- static assert_failed()
- {
- write(2, "assert failed in lib/malloc.c\n", 30);
- abort();
- }
- #endif
-
- #ifdef __MSHORT__
- _VOIDSTAR malloc(n)
- unsigned int n;
- { return lmalloc((unsigned long)n); }
-
- _VOIDSTAR realloc(old, n)
- _VOIDSTAR old;
- unsigned int n;
- { return lrealloc(old, (unsigned long)n); }
-
- _VOIDSTAR calloc(n, m)
- unsigned int n, m;
- { return lcalloc((unsigned long)n, (unsigned long)m); }
- #endif
-